package com.zecan.blog.controller.interceptor;

import cn.hutool.json.JSONUtil;
import com.zecan.blog.common.status.UserStatus;
import com.zecan.blog.controller.annotation.AccessLimit;
import com.zecan.blog.utils.BlogConstant;
import com.zecan.blog.utils.BlogResultUtils;
import com.zecan.blog.utils.RedisUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 限制访问拦截器
 * @author zecan
 * @Description:
 * @ClassName: AccessLimitInterceptor
 * @date 2022/12/15 18:27
 */


@Component
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Resource
    private RedisUtils redisUtils;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 如果当前执行的是方法
        if(handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
//            System.out.println(hm.getMethod().getName());

            // 获取注解
            AccessLimit ano = hm.getMethodAnnotation(AccessLimit.class);
            // 如果没有限制则直接放行
            if(ano == null) {
                return true;
            }
            // 如果有注解说明有限制信息，则进行获取信息进行保存redis备份
            // 获取限制秒数以及最大访问次数以及用户的id
            int seconds = ano.seconds();
            int maxCount = ano.maxCount();
            String uri = request.getRequestURI();
            // 修改信息拦截
            if(uri.equals("/user/update/userInfo")) {
                return updateUserInfoAccessLimit(request,response,seconds,maxCount);
            }

            // 获取验证码拦截
            if(uri.equals("/user/emailCaptcha")) {
                return sendEmailCaptchaAccessLimit(request,response,seconds,maxCount);
            }

            // 收藏拦截
            if(uri.equals("/article/addStar")) {
                return addStarAccessLimit(request,response,seconds,maxCount);
            }
            // 点赞拦截
            if(uri.equals("/article/addGood")) {
                return addGoodAccessLimit(request,response,seconds,maxCount);
            }
        }

        return true;
    }




    /**
     * 修改用户信息拦截方法
     * @param request
     * @param response
     * @param seconds 注解中的秒数
     * @param maxCount 最大访问次数
     * @return
     * @throws IOException
     */
    private boolean updateUserInfoAccessLimit(HttpServletRequest request,HttpServletResponse response,int seconds, int maxCount) throws IOException {
        String userId = request.getParameter("userId");
        // 在redis中获取数据
        Integer redisMaxCount = (Integer) redisUtils.hashGet(BlogConstant.UPDATE_USER_LIMIT + userId, String.valueOf(seconds));
        // 如果此时是第一次进行访问直接放行
        if(redisMaxCount == null) {
            // 存储redis
            redisUtils.hashSet(BlogConstant.UPDATE_USER_LIMIT + userId,String.valueOf(seconds),1,seconds);
            return  true;
        }else if(Math.max(redisMaxCount,maxCount) == redisMaxCount) {
            response.setContentType("application/json;charset=UTF-8");
            ServletOutputStream outputStream = response.getOutputStream();
            // 提示写入
            outputStream.write(JSONUtil.toJsonStr(
                    BlogResultUtils.userStatus(UserStatus.USER_UPDATE_INFO_ACCESS_LIMIT)
            ).getBytes(StandardCharsets.UTF_8));
            return false;
        }
        return true;

    }

    /**
     * 发送验证码拦截方法
     * @param request
     * @param response
     * @param seconds
     * @param maxCount
     * @return
     */
    private boolean sendEmailCaptchaAccessLimit(HttpServletRequest request,HttpServletResponse response,int seconds, int maxCount) throws IOException {
        // 获取请求头中的数据
        String email = request.getParameter("email");

        // redis 中获取是否已经获取过验证码
        Integer redisMaxCount = (Integer) redisUtils.hashGet(BlogConstant.SEND_EMAIL_LIMIT + email, email);

        // 如果是第一次进行发送验证码
        if(redisMaxCount == null) {
            // 保存到redis中
            redisUtils.hashSet(BlogConstant.SEND_EMAIL_LIMIT + email, email,1,seconds);
            return true;
        }else if (Math.max(redisMaxCount,maxCount) == redisMaxCount) {
            response.setContentType("application/json;charset=UTF-8");

            // 响应信息
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(JSONUtil.toJsonStr(
                    BlogResultUtils.userStatus(UserStatus.USER_SEND_EMAIL_ACCESS_LIMIT)
                    ).getBytes(StandardCharsets.UTF_8)
            );
            return false;
        }
        return true;
    }

    /**
     * 点赞防止抖动拦截
     * @param request request
     * @param response response
     * @param seconds 拦截秒数
     * @param maxCount 最大访问次数
     * @return
     * @throws IOException
     */
    private boolean addGoodAccessLimit(HttpServletRequest request,HttpServletResponse response,int seconds, int maxCount) throws IOException {
        // 获取请求头中的数据
        String userId = request.getParameter("userId");
        String articleId = request.getParameter("articleId");

        // redis 中获取是否已经获取点赞过
        Integer redisMaxCount = (Integer) redisUtils.hashGet(BlogConstant.ARTICLE_ADD_GOOD_LIMIT + userId + ":" + articleId, articleId);

        // 如果是第一次进行点赞
        if(redisMaxCount == null) {
            // 保存到redis中
            redisUtils.hashSet(BlogConstant.ARTICLE_ADD_GOOD_LIMIT + userId + ":" + articleId, articleId,1,seconds);
            return true;
        }else if (Math.max(redisMaxCount,maxCount) == redisMaxCount) {

            response.setContentType("application/json;charset=UTF-8");

            // 响应信息
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(JSONUtil.toJsonStr(
                            BlogResultUtils.userStatus(UserStatus.USER_ADD_GOOD_ACCESS_LIMIT)
                    ).getBytes(StandardCharsets.UTF_8)
            );
            return false;
        }else {
            // 如果没有超出 则进行增加数量
            redisUtils.hashIncr(BlogConstant.ARTICLE_ADD_GOOD_LIMIT + userId + ":" + articleId, articleId,1);
        }
        return true;
    }

    /**
     * 收藏防抖
     * @param request
     * @param response
     * @param seconds
     * @param maxCount
     * @return
     */
    private boolean addStarAccessLimit(HttpServletRequest request, HttpServletResponse response, int seconds, int maxCount) throws IOException {
        // 获取请求头中的数据
        String userId = request.getParameter("userId");
        String articleId = request.getParameter("articleId");

        // redis 中获取是否已经获取过验证码
        Integer redisMaxCount = (Integer) redisUtils.hashGet(BlogConstant.ARTICLE_ADD_STAR_LIMIT + userId + ":" + articleId, articleId);

        // 如果是第一次进行发送验证码
        if(redisMaxCount == null) {
            // 保存到redis中
            redisUtils.hashSet(BlogConstant.ARTICLE_ADD_STAR_LIMIT + userId + ":" + articleId, articleId,1,seconds);
            return true;
        }else if (Math.max(redisMaxCount,maxCount) == redisMaxCount) {
            response.setContentType("application/json;charset=UTF-8");

            // 响应信息
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(JSONUtil.toJsonStr(
                            BlogResultUtils.userStatus(UserStatus.USER_ADD_STAR_ACCESS_LIMIT    )
                    ).getBytes(StandardCharsets.UTF_8)
            );
            return false;
        }else {
            // 如果没有超出则进行添加
            redisUtils.hashIncr(BlogConstant.ARTICLE_ADD_STAR_LIMIT + userId + ":" + articleId, articleId,1);
        }
        return true;
    }
}
